# -*-coding:utf-8-*-

import random
import math
import xml.dom.minidom
import json

try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO


def print_obj(obj):
    print json.dumps(obj, indent=4, ensure_ascii=False).encode('utf-8')


def extract_fields(src, required_fields=None, optional_fields=None):
    result = {}
    if required_fields is not None:
        for f in required_fields:
            result[f] = src[f]
    if optional_fields is not None:
        for f in optional_fields:
            if f in src:
                result[f] = src[f]
    return result


def exclude_fields(src, exclusive_fields):
        f_to_del = []
        for f in src.iterkeys():
            if f in exclusive_fields:
                f_to_del.append(f)
        for f in f_to_del:
            del src[f]


def generate_random_no(length):
    f = int(math.pow(10, length - 1))
    t = int(math.pow(10, length)) - 1
    return random.randint(f, t)


def node_from_dict(dom, r, d):
    for k, v in d.iteritems():
        if isinstance(k, unicode):
            k = k.encode('utf-8')
        e = dom.createElement(k)
        if isinstance(v, dict):
            node_from_dict(dom, e, v)
        else:
            if isinstance(v, unicode):
                v = v.encode('utf-8')
            if not isinstance(v, str):
                v = str(v)
            t = dom.createTextNode(v)
            e.appendChild(t)
        r.appendChild(e)


def dict_to_xml(d, encoding=None, header=False, root_tag_name='xml'):
    impl = xml.dom.minidom.getDOMImplementation()
    dom = impl.createDocument(None, root_tag_name, None)
    r = dom.documentElement
    node_from_dict(dom, r, d)
    # x = dom.toxml(encoding)
    # NOTE: cStringIO 不能处理 unicode, 所以在 node_from_dict 中 key/value 都转成 utf-8
    # 也因此，在此模块中的 dict/xml 转换函数只能支持 utf-8 编码
    writer = StringIO()
    dom.writexml(writer, '', '', '', encoding)
    x = writer.getvalue()
    if header:
        return x
    else:
        return x[x.find('?>') + 2:]


def dict_to_xml_old(d):
    impl = xml.dom.minidom.getDOMImplementation()
    dom = impl.createDocument(None, 'xml', None)
    root = dom.documentElement
    for k, v in d.iteritems():
        e = dom.createElement(k)
        t = dom.createTextNode(str(v))
        e.appendChild(t)
        root.appendChild(e)
    x = dom.toxml()
    return x[x.find('?>') + 2:]


# 有 CDATA node，如微信， 应 skip CDATA node 外层的 TEXT node
def node_to_dict(r):
    d = {}
    for e in r.childNodes:
        # Node.ELEMENT_NODE = 2,
        # Node.TEXT_NODE = 3,
        # Node.CDATA_SECTION_NODE = 4,
        # print e.nodeType, e.nodeName, e.nodeValue
        if e.nodeType == e.ELEMENT_NODE:
            val = node_to_dict(e)
            if 0 < len(val):
                d[e.nodeName] = val
        elif e.nodeType == e.CDATA_SECTION_NODE:
            return e.nodeValue
        elif e.nodeType == e.TEXT_NODE:
            # avoid indents(\t or spaces)
            if '' != e.nodeValue.strip():
                return e.nodeValue
    return d


def dict_from_xml(x):
    dom = xml.dom.minidom.parseString(x)
    r = dom.documentElement
    return node_to_dict(r)


def dict_from_xml_old(x):
    dom = xml.dom.minidom.parseString(x)
    root = dom.documentElement
    d = {}
    for e in root.childNodes:
        if e.nodeType == e.ELEMENT_NODE:
            if 0 == len(e.childNodes):
                # d[e.nodeName] = ''
                pass
            else:
                d[e.nodeName] = e.childNodes[0].nodeValue
    return d


def limit_update_scope(update, scope='specifics'):
    limited_update = dict()
    for k, v in update.iteritems():
        vv = dict()
        for f in v.iterkeys():
            vv['%s.%s' % (scope, f)] = v[f]
        limited_update[k] = vv
    return limited_update


def test1():
    x = '<xml><spce><a>1</a><b>2</b></spce><age>0</age><name>foo</name></xml>'
    x = '<FOO><spce><a><aa>周</aa><a2>12</a2></a><b>2</b></spce><age>0</age><name>foo</name></FOO>'
    d = dict_from_xml(x)
    print d
    x = dict_to_xml(d, encoding='utf-8', header=True, root_tag_name='BAR')
    x = x.replace('<?xml version="1.0" encoding="utf-8"?>', '<?xml version="1.0" encoding="GBK"?>')
    print x
    x = x.replace('<?xml version="1.0" encoding="GBK"?>', '<?xml version="1.0" encoding="utf-8"?>')
    d = dict_from_xml(x)
    print d

    x = '''<?xml version="1.0" encoding="utf-8"?><AIPG>
  <INFO>
    <TRX_CODE>100014</TRX_CODE>
    <VERSION>03</VERSION>
    <DATA_TYPE>2</DATA_TYPE>
    <REQ_SN>200603000001374_5a5037c395004cfeddf1a400</REQ_SN>
    <RET_CODE>2007</RET_CODE>
    <ERR_MSG>未开通的业务类型</ERR_MSG>
    <SIGNED_MSG>61824448de2911d57225ad9504815648e47432ebc13e429925fef4365228607cd0fc998e6c729318f67e74222ef353ac265b619f341381e9196735c76c70beff669359253a590c28c5db63f36a237731ca73aad658d5c26873e8051efed68e8b957deface44175cc9a5cf26ca1425359699d8595cbfe772673db4104d3a35d38ecd8d56a801b63f21b8f8c0b2dd3f4f069d4ef43a27e7ced976c2a36203568d3e280afef3eb4cdfe202db90d2f096c747fe08d18dc1d0aab1a02b97002188e763ba1dd4b944eca4cbb3f6989a6cdfb49f110c41fc2c4c36a960a6af7dd74e31720ed00503c59d1df75b13c19881972ea3a6075da43a32a5afee5518347ec9ffd</SIGNED_MSG>
  </INFO>
</AIPG>'''
    x = x.replace('\n', '')
    x = x.replace('  ', '')
    x = x.replace('  ', '')
    print x
    d = dict_from_xml(x)
    print d


def test2():
    # '\xe5\xbe\xae\xe4\xbf\xa1\xe6\x94\xaf\xe4\xbb\x98'
    d = {'body': '\xe5\xbe\xae\xe4\xbf\xa1\xe6\x94\xaf\xe4\xbb\x98', 'openid': 'oPDmD0dPLgToa2MEsOscDX2vK68s',
         'trade_type': 'JSAPI', 'nonce_str': '5a657cda97c2095fea0cd2a5', 'sign': '9BCE86F3EB459630F9C1E1F65D15C2D0',
         'mch_id': '1480183932',
         'notify_url': 'http://sdw.hifocus.top/api/orders/5a657cd997c2095fea0cd2a3/wx/pay/on_notify',
         'spbill_create_ip': '120.25.220.159', 'device_info': 'WEB', 'out_trade_no': '5a657cd997c2095fea0cd2a3',
         'total_fee': 10, 'appid': 'wxa979ac87742efd30'}
    # d['body'] = d['body'].decode('utf-8')
    x = dict_to_xml(d)
    print type(x), x

    x = '''<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>
    <return_msg><![CDATA[OK]]></return_msg>
    <appid><![CDATA[wxa979ac87742efd30]]></appid>
    <mch_id><![CDATA[1480183932]]></mch_id>
    <device_info><![CDATA[WEB]]></device_info>
    <nonce_str><![CDATA[7rnB5SaM4PCNFvqN]]></nonce_str>
    <sign><![CDATA[9C04192580509E0AC67862985D7B6912]]></sign>
    <result_code><![CDATA[SUCCESS]]></result_code>
    <prepay_id><![CDATA[wx20180122155849009d4088300895510290]]></prepay_id>
    <trade_type><![CDATA[JSAPI]]></trade_type>
    <total_fee>10</total_fee>
    </xml>'''
    d = dict_from_xml(x)
    print 'result:\n', d


if '__main__' == __name__:
    test1()
    test2()

